﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Linq;
using System.Reflection;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.DependencyInjection;
using Xms.Abp.Storage.Migrator;

namespace Xms.Abp.Storage.DependencyInjection;

public static class XmsStorageServiceCollectionExtensions
{
    public static IServiceCollection AddStorage<TStorage>(this IServiceCollection services,
        Action<IXmsStorageRegistrationOptionsBuilder> optionsBuilder = null,
        Action<XmsStorageConfigurationOptions<TStorage>> storageOptionsBuilder = null)
        where TStorage : XmsStorage<TStorage>
    {
        services.AddMemoryCache();

        if (storageOptionsBuilder != null)
        {
            services.Configure(storageOptionsBuilder);
        }

        services.TryAddTransient(DbContextOptionsFactory.Create<TStorage>);



        //var connectionName = ConnectionStringNameAttribute.GetConnStringName<TStorage>();
        //var configuration = services.GetConfiguration();
        //var connectionString = configuration.GetConnectionString(connectionName);
        //var dbType = connectionString.Contains("DbType") ? connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(r => r.StartsWith("DbType=")) : "MySql";
        //var defaultDbType = configuration["DbContextOptions:DefaultDbType"] ?? "MySql";

        //if (defaultDbType != dbType)
        //{
        //    services.Configure<AbpDbContextOptions>(options =>
        //    {
        //        options.Configure<TStorage>(ctx =>
        //        {
        //            var builder = dbType.ToLower() switch
        //            {
        //                "postgresql" => ctx.UseNpgsql(),
        //                "sqlserver" => ctx.UseSqlServer(),
        //                //"oracle" => ctx.UseOracle(),
        //                "sqlite" => ctx.UseSqlite(),
        //                "mysql" => ctx.UseMySQL(),
        //                _ => ctx.UseMySQL()
        //            };
        //        });
        //    });
        //}

        var options = new XmsStorageRegistrationOptions(typeof(TStorage), services);
        options.AddDefaultRepositories(true);
        optionsBuilder?.Invoke(options);

        services.AddTransient<IStorageMigrator, StorageMigrator<TStorage>>();

        foreach (var dbContextType in options.ReplacedDbContextTypes)
        {
            var targetDbContextType = dbContextType.Value ?? typeof(TStorage);
            services.Replace(ServiceDescriptor.Transient(dbContextType.Key, targetDbContextType));

            var removeMigrator = typeof(StorageMigrator<>).MakeGenericType(dbContextType.Key);
            var removeItem = services.FirstOrDefault(r => r.ServiceType == typeof(IStorageMigrator) && r.ImplementationType == removeMigrator);
            if (removeItem != null)
                services.Remove(removeItem);

            services.Configure<AbpDbContextOptions>(opts =>
            {
                opts.GetDbContextReplacements()[dbContextType.Key] = targetDbContextType;
            });
        }

        //new EfCoreRepositoryRegistrar(options).AddRepositories();
        new XmsStorageRepositoryRegistrar(options).AddRepositories();

        return services;
    }

    public static IServiceCollection AddStorage<TStorage>(this IServiceCollection services, string tablePrefix = null, string schema = null, Action<IXmsStorageRegistrationOptionsBuilder> optionsBuilder = null)
        where TStorage : XmsStorage<TStorage>
    {
        return services.AddStorage<TStorage>(optionsBuilder, options =>
        {
            options.TablePrefix = tablePrefix;
            options.Schema = schema;
        });
    }
}
